﻿// The VIPER Executable format , .GEX 
// This class can be used to load .GEX files and read there contents


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
public enum ApplicationType
{
    Viper = 1,
    XVM = 2,
    Gruntscript = 3,
}
public class GEXResource
{
  public string Name;
        public byte[] Data;
}
public class GEX
{
    public string ApplicationName,ApplicationAuthor,CreatorUsername,DefaultPackage,Checksum;
    public uint Version;
    public string Timestamp;
    public ApplicationType AppType;
    BinaryWriter bw;
    public GEX(string Filename)
    {
        
        Fname = Filename;
    }
    string Fname;
    public List<GEXResource> Files = new List<GEXResource>();
    public int CodeStart = 0;
    public List<string> DLLs = new List<string>();
    public GEXResource LoadFile(string file)
    {
        foreach (GEXResource f in Files)
        {
            if (f.Name == file)
            {
                return f;
            }
        }
        return null;
    }
    public static GEX LoadFromFile(string Filename)
    {
            GEX final = new GEX(Filename);
            BinaryReader br = new BinaryReader(new FileStream(Filename,FileMode.Open));
        
            br.BaseStream.Position = 20;
            final.ApplicationName = br.ReadString();
            final.ApplicationAuthor = br.ReadString();
            final.CreatorUsername = br.ReadString();
            final.DefaultPackage = br.ReadString();
            br.ReadInt32();
            final.Version = br.ReadUInt32();
            final.CodeStart = br.ReadInt32();
            final.Timestamp = br.ReadString();
            final.Checksum = br.ReadString();
            int DLLlength = br.ReadInt32();
            while (DLLlength > final.DLLs.Count)
            {
                final.DLLs.Add(br.ReadString());
            }
            while (true)
            {
                try
                {
                    string name = br.ReadString();
                    GEXResource f = new GEXResource();
                    f.Name = name;
                    int length = br.ReadInt32(); 
                    f.Data = new byte[length];
                    for (int i = 0; i < length; i++)
                    {
                        f.Data[i] = br.ReadByte();
                    }
                    final.Files.Add(f);
                }
                catch
                {
                    break;
                }
            }
            br.Close();
            return final;
        
        
    }
    public int GetHash(byte[] data)
    {
        int fin = 0;
        int i = 0;
        foreach (byte b in data)
        {
            fin += b & i;
            i++;
        }
        return i;
    }
    public uint devID = 0;
    public bool Signed = false;
    public void Save(bool Sign = false)
    {
        bw = new BinaryWriter(new FileStream(Fname, FileMode.Create));
        bw.Write('G');
        bw.Write('E');
        bw.Write('X');
        bw.Write('3');
        bw.Write(' ');
        bw.Write('S');
        bw.Write('C');
        bw.BaseStream.Position = 20;
        bw.Write(ApplicationName);
        bw.Write(ApplicationAuthor);
        bw.Write(CreatorUsername);
        bw.Write(DefaultPackage);
        bw.Write((int)AppType);
        bw.Write(Version);
        bw.Write(CodeStart);
        bw.Write("Created At: " + DateTime.Now.ToString("HH:mm:ss tt"));
        if (Sign)
        {
            foreach(GEXResource g in this.Files)
            {
                Checksum += GetHash(g.Data) + GetHash(Encoding.ASCII.GetBytes(ApplicationAuthor));
            }
        }
        bw.Write(Checksum);
        bw.Write(DLLs.Count);
        foreach (string s in DLLs)
        {
            bw.Write(s);
        }
        foreach (GEXResource file in Files)
        {
            bw.Write(file.Name);
            bw.Write((Int32)file.Data.Length);
            bw.Write(file.Data);
        }
        bw.Close();
    }
}